package com.ifgostudio.framework.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * <b>Description</b>:计算给定文件或者字符串的HASH摘要<br/>
 * <b>Author</b>: linxuexin<br/>
 * <b>Link</b>: Email:<a href="mailto:linxuexin0423@gmail.com">linxuexin0423@gmail.com</a>;Telephone:13799286849;QQ:30268646;林先生<br/>
 * <b>Copyright</b>: <a href="http://www.ifgostudio.com" target="_blank">www.ifgostudio.com</a> all rights reserved<br/>
 * <b>Information</b>: 对外承接网站制作,价格优惠,服务一流,强有力的技术支持,asp,Jsp,Hibernate,Struts2,MS SQLServer,Oracle,jQuery,Css+div布局,Dhtml<br/>
 * <b>Create Date</b>: Dec 2, 2008 5:22:45 PM<br/>
 * <b>Version</b>: Since JDK 1.5.0<br/>
 * <b>Package</b>: com.ifgostudio.framework.util
 */
public class HashCalc
{
	private static char[] hexChar = {'0','1','2','3','4','5','6','7','8', '9','a','b','c','d','e','f'};
	
	/**
	 * 把字节数组转换成16进制的字符串
	 * @param b 字节数组
	 * @return 16进制的字符串
	 */
	public static String toHexString(byte[] b)
	{
		StringBuffer sb = new StringBuffer(b.length * 2);
		for (int i = 0; i < b.length; i++) 
		{
			sb.append(hexChar[ (b[i] & 0xf0) >>> 4]);
			sb.append(hexChar[b[i] & 0x0f]);
		}
		return sb.toString();
	}
	/**
	 * 取得文件的MD5摘要
	 * @param filepath 文件路径
	 * @return 消息摘要的16进制结果
	 */
	public static String getMD5HashDigest(String filepath)
	{
		return getHashDigest(filepath,"MD5");
	}
	/**
	 * 取得文件的SHA1摘要
	 * @param file 要取得文件摘要的文件
	 * @return 消息摘要的16进制结果
	 */
	public static String getSHAHashDigest(File file)
	{
		return getHashDigest(file,"SHA1");
	}
	/**
	 * 取得文件的SHA1摘要
	 * @param filepath 文件路径
	 * @return 消息摘要的16进制结果
	 */
	public static String getSHAHashDigest(String filepath)
	{
		return getHashDigest(filepath,"SHA1");
	}
	/**
	 * 取得文件的MD5摘要
	 * @param file 要取得文件摘要的文件
	 * @return 消息摘要的16进制结果
	 */
	public static String getMD5HashDigest(File file)
	{
		return getHashDigest(file,"MD5");
	}
	/**
	 * 取得指定类型文件的消息摘要
	 * @param filepath 要取得文件摘要的文件路径
	 * @param hashType 计算消息摘要的类型,如:"MD2", "MD5", "SHA1", "SHA-256", "SHA-384", "SHA-512"
	 * @return 消息摘要的16进制结果
	 */
	public static String getHashDigest(String filepath,String hashType)
	{
		File file = new File(filepath);
		return getHashDigest(file,hashType);
	}
	
	/**
	 * 取得指定类型文件的消息摘要
	 * @param file 要取得文件摘要的文件
	 * @param hashType 计算消息摘要的类型,如:"MD2", "MD5", "SHA1", "SHA-256", "SHA-384", "SHA-512"
	 * @return 消息摘要的16进制结果
	 */
	public static String getHashDigest(File file,String hashType)
	{
		MessageDigest md = null;
		InputStream fis = null;
		byte[] buffer = new byte[1024];
		try
		{
			md = MessageDigest.getInstance(hashType);
			fis = new FileInputStream(file);
			int numRead = 0;
			while ((numRead = fis.read(buffer)) > 0)
			{
				md.update(buffer, 0, numRead);
			}
			return toHexString(md.digest());
		}
		catch(NoSuchAlgorithmException e)
		{
			e.printStackTrace();
			return null;
		}
		catch(FileNotFoundException e)
		{
			e.printStackTrace();
			return null;
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return null;
		}
		finally
		{
			if (fis != null)
			{
				try
				{
					fis.close();
				}
				catch(IOException e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	/**
	 * 取得指定摘要类型字符串的消息摘要
	 * @param content 要进行摘要计算的字符串
	 * @param hashType 进行摘要计算的类型
	 * @return 消息摘要的16进制结果
	 */
	public static String getStringHashDigest(String content,String hashType)
	{
		MessageDigest md;
		try
		{
			md = MessageDigest.getInstance(hashType);
		}
		catch(NoSuchAlgorithmException e)
		{
			e.printStackTrace();
			return null;
		}
		return toHexString(md.digest(content.getBytes()));
	}
	/**
	 * 取得字符串的MD5消息摘要
	 * @param content 要进行摘要计算的字符串
	 * @return 消息摘要的16进制结果
	 */
	public static String getStringMD5Hash(String content)
	{
		return getStringHashDigest(content,"MD5");
	}
	/**
	 * 取得字符串的SHA消息摘要
	 * @param content 要进行摘要计算的字符串
	 * @return 消息摘要的16进制结果
	 */
	public static String getStringSHAHash(String content)
	{
		return getStringHashDigest(content,"SHA");
	}
	/**
	 * 给定的字节数组按比特位输出结果
	 * @param b 字节数组
	 * @return 比特位字符串
	 */
	public static String getBits(byte[] b)
	{
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < b.length; i++)
		{
			for(int j =7 ;j >=0; j--)
				sb.append((b[i] & (0x1<<j))>>>j);
		}
		return sb.toString();
	}
	/**
	 * 设置hash计算码表,默认是[0123456789abcdef]
	 * @param hexChar 新的码表
	 */
	public static void setHexChar(char[] hexChar)
	{
		synchronized(HashCalc.hexChar)
		{
			HashCalc.hexChar = hexChar;
		}		
	}
	/**
	 * 使用例子
	 * @param args
	 */
	public static void main(String[] args)
	{
//		System.out.println(HashCalc.getHashDigest("c:/Splash.bmp","MD2"));
//		System.out.println(HashCalc.getMD5HashDigest("c:/Splash.bmp"));
//		System.out.println(HashCalc.getSHAHashDigest("c:/Splash.bmp"));
//		System.out.println(HashCalc.getHashDigest("c:/Splash.bmp","SHA1"));
//		System.out.println(HashCalc.getHashDigest("c:/Splash.bmp","SHA-256"));
//		System.out.println(HashCalc.getHashDigest("c:/Splash.bmp","SHA-384"));
//		System.out.println(HashCalc.getHashDigest("c:/Splash.bmp","SHA-512"));
		System.out.println(HashCalc.getBits("1".getBytes()));
	}
}
